package com.hades.xq.seckill.service.impl;

import com.alibaba.druid.util.StringUtils;
import com.hades.xq.seckill.base.CommonReturnType;
import com.hades.xq.seckill.base.EmBusinessError;
import com.hades.xq.seckill.dao.TbSeckillMapper;
import com.hades.xq.seckill.dao.TbSuccessKilledMapper;
import com.hades.xq.seckill.dao.dto.TbSeckill;
import com.hades.xq.seckill.dao.dto.TbSuccessKilled;
import com.hades.xq.seckill.exceptions.RepeatKillException;
import com.hades.xq.seckill.exceptions.SeckillClosedException;
import com.hades.xq.seckill.exceptions.SeckillException;
import com.hades.xq.seckill.service.SeckillService;
import com.hades.xq.seckill.service.model.ExportSeckillUrlModel;
import com.hades.xq.seckill.service.model.SeckillExecution;
import com.hades.xq.seckill.service.model.SuccessKilled;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;

import java.util.Date;
import java.util.List;

/**
 * @ClassName SeckillServiceimpl
 * @Description 秒杀service
 * @Author Hades
 * @Date 2019-03-19:14:47
 * @Version V1.0.0
 */
@Slf4j
@Service
public class SeckillServiceImpl implements SeckillService {

    private final static String salf = "12sfasf3rwerwf!*@(@JJJJJ";

    @Autowired
    private TbSeckillMapper seckillMapper;

    @Autowired
    private TbSuccessKilledMapper successKilledMapper;

    @Override
    @Transactional
    public int reduceNumber(Long seckillId, Date killTime) {
        return seckillMapper.reduceNumber(seckillId, killTime);
    }

    @Override
    public TbSeckill quaryById(Long seckillId) {
        return seckillMapper.quaryById(seckillId);
    }

    @Override
    public List<TbSeckill> quaryAll(int offet, int limit) {
        return seckillMapper.quaryAll(offet, limit);
    }

    @Override
    public CommonReturnType exportSeckillUrl(Long seckillId) throws RepeatKillException {

        if (seckillId == null || seckillId < 0) {
            throw new RepeatKillException(EmBusinessError.PARAMETER_VALIDATION_ERROR);
        }
        TbSeckill seckill = seckillMapper.quaryById(seckillId);
        if (seckill == null) {
            return CommonReturnType.createFail(new ExportSeckillUrlModel(false, seckillId), "获取秒杀数据失败");
        }
        Date startDate = seckill.getStartTime();
        Date endDate = seckill.getEndTime();
        //获取系统当前时间
        Date nowDate = new Date();
        if (nowDate.getTime() < startDate.getTime() || nowDate.getTime() > endDate.getTime()) {
            return CommonReturnType.createFail(new ExportSeckillUrlModel(false, seckillId, nowDate, startDate, endDate), "秒杀还未开始或已经结束");
        }
        String md5 = getMd5(seckillId);
        return CommonReturnType.create(new ExportSeckillUrlModel(true, seckillId, md5, nowDate, startDate, endDate), "获取秒杀数据成功");
    }

    @Override
    @Transactional
    public CommonReturnType executeSeckill(Long seckillId, Long userPhone, String md5) throws SeckillException, SeckillClosedException, RepeatKillException {
        if (seckillId == null || seckillId < 0) {
            throw new SeckillException(EmBusinessError.PARAMETER_VALIDATION_ERROR);
        }
        if (userPhone == null || userPhone < 0) {
            throw new SeckillException(EmBusinessError.PARAMETER_VALIDATION_ERROR);
        }
        if (StringUtils.isEmpty(md5) || !md5.equals(getMd5(seckillId))) {
            throw new SeckillException(EmBusinessError.MD5_UNKNOW_ERROR);
        }
        // 秒杀逻辑 1 减库存，2 插入明细
        Date now = new Date();
        //减库存
        try {
            int offRow = seckillMapper.reduceNumber(seckillId, now);
            if (offRow <= 0) {
                throw new SeckillClosedException(EmBusinessError.SECKILL_CLOSED);
            } else {
                //记录购买行为
                int insertNum = successKilledMapper.insertSuccessKilled(seckillId, userPhone);
                if (insertNum <= 0) {
                    //重复秒杀
                    throw new RepeatKillException(EmBusinessError.SECKILL_REPEAT);
                } else {
                    TbSuccessKilled successKilled = successKilledMapper.quaryByIdWithSeckill(seckillId);
                    SeckillExecution seckillExecution = conertModelFromDTO(successKilled);
                    return CommonReturnType.create(seckillExecution, "秒杀成功");
                }
            }
        } catch (RepeatKillException e1) {
            log.error(e1.getErrirMsg());
            throw e1;
        } catch (SeckillClosedException e2) {
            log.error(e2.getErrirMsg());
            throw e2;
        } catch (SeckillException e3) {
            log.error(e3.getErrirMsg());
            throw e3;
        } catch (Exception e4) {
            throw new SeckillException(EmBusinessError.UNKNOW_ERROR);
        }
    }

    private SeckillExecution conertModelFromDTO(TbSuccessKilled tbSuccessKilled) {
        SeckillExecution seckillExecution = new SeckillExecution();
        seckillExecution.setStatus(1);
        seckillExecution.setStatusInfo("秒杀成功");
        if (tbSuccessKilled != null) {
            SuccessKilled successKilled = new SuccessKilled();
            BeanUtils.copyProperties(tbSuccessKilled, successKilled);
            seckillExecution.setSuccessKilled(successKilled);
        }
        return seckillExecution;
    }

    private String getMd5(Long seckillId) {
        String md5 = seckillId + "/" + salf;
        return DigestUtils.md5DigestAsHex(md5.getBytes());
    }
}
